﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Devonline.AspNetCore;

/// <summary>
/// 基于 IAttachmentService 附件及文件操作类服务
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TAttachment">附件数据类型</typeparam>
/// <typeparam name="TKey">主键类型</typeparam>
[Authorize]
[ApiController]
public abstract class AttachmentServiceController<TDbContext, TAttachment, TKey>(
    ILogger<AttachmentServiceController<TDbContext, TAttachment, TKey>> logger,
    IDataService<TDbContext, TAttachment, TKey> dataService,
    IAttachmentService<TDbContext, TAttachment, TKey> attachmentService,
    IFileService fileService) :
    ControllerBase
    where TDbContext : DbContext
    where TAttachment : class, IAttachment<TKey>, new()
    where TKey : IConvertible
{
    protected readonly ILogger<AttachmentServiceController<TDbContext, TAttachment, TKey>> _logger = logger;
    protected readonly IDataService<TDbContext, TAttachment, TKey> _dataService = dataService;
    protected readonly IAttachmentService<TDbContext, TAttachment, TKey> _attachmentService = attachmentService;
    protected readonly IFileService _fileService = fileService;

    /// <summary>
    /// 使用限定的 businessType 和 businessKey 获取附件
    /// </summary>
    /// <param name="businessType"></param>
    /// <param name="businessKey"></param>
    /// <returns></returns>
    [HttpGet]
    public virtual async Task<IActionResult> GetAsync(TKey businessKey, string? businessType = default)
    {
        var attachments = await _attachmentService.GetAttachmentsAsync(businessKey, businessType);
        return attachments == null ? NotFound() : Ok(attachments);
    }

    /// <summary>
    /// 附件下载, 提供完整文件相对路径的单个文件下载, 且文件必须是已入库附件
    /// </summary>
    /// <param name="fileName">完整的相对路径文件名</param>
    /// <returns></returns>
    [HttpGet("Download")]
    public virtual async Task<IActionResult> DownloadAsync(string fileName) => await _attachmentService.GetAttachmentFileAsync(fileName);
    /// <summary>
    /// 文件下载, 提供类似于文件夹目录结构的访问方式进行下载
    /// 文件路径只支持一级路径, 适用于访问自动保存的文件或者符合目录规范的文件
    /// </summary>
    /// <param name="filePath">文件路径(只支持一级路径)</param>
    /// <param name="fileName">文件名</param>
    /// <returns></returns>
    [HttpGet("Files/{filePath}/{fileName}")]
    public virtual async Task<IActionResult> FilesAsync(string filePath, string fileName) => await _attachmentService.GetFileAsync(Path.Combine(filePath, fileName));
    /// <summary>
    /// 文件下载, 提供类似于文件夹目录结构的访问方式进行下载
    /// </summary>
    /// <param name="fileName">完整的相对路径文件名</param>
    /// <returns></returns>
    [HttpGet("Files")]
    public virtual async Task<IActionResult> FilesAsync(string fileName) => await _attachmentService.GetFileAsync(fileName);

    /// <summary>
    /// 新增单个数据对象的 post 请求
    /// </summary>
    /// <param name="attachment">需要保存的附件</param>
    /// <returns></returns>
    [HttpPost]
    public virtual async Task<IActionResult> CreateAsync(TAttachment attachment)
    {
        if (attachment.BusinessKey is null)
        {
            return BadRequest("缺少业务数据申明!");
        }

        if (_attachmentService is not IDataService<TDbContext, TAttachment, TKey> dataService || dataService is null)
        {
            throw new InvalidCastException($"无法将类型 IAttachmentService<TDbContext, TAttachment, TKey> 的实例转换为类型 : IDataService<TDbContext, TAttachment, TKey>");
        }

        return Ok(await dataService.AddAsync(attachment));
    }
    /// <summary>
    /// 修改单个数据对象的 put 请求
    /// </summary>
    /// <param name="entitySet"></param>
    /// <returns></returns>
    [HttpPut]
    public virtual async Task<IActionResult> UpdateAsync(TAttachment attachment) => Ok(await _dataService.UpdateAsync(attachment));

    /// <summary>
    /// 文件上传, 支持批量上传, 返回 UploadResult 集合
    /// </summary>
    /// <param name="files"></param>
    /// <returns></returns>
    [HttpPost("Upload")]
    public virtual async Task<IActionResult> UploadAsync(IEnumerable<IFormFile> files) => Ok(await _attachmentService.UploadAsync(files));

    /// <summary>
    /// 使用 id 删除单个数据对象的 delete 请求
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpDelete("{id}")]
    public virtual async Task<IActionResult> DeleteAsync(TKey id)
    {
        await _dataService.DeleteAsync(id);
        return Ok();
    }
    /// <summary>
    /// 文件删除, 支持由逗号间隔的文件名批量删除
    /// </summary>
    /// <param name="fileNames"></param>
    /// <returns></returns>
    [HttpDelete("Delete")]
    public virtual IActionResult Delete(string fileNames)
    {
        var files = fileNames.Split(AppSettings.CHAR_COMMA, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        if (files.Length != 0)
        {
            _fileService.DeleteFiles(files);
        }

        return Ok();
    }
    /// <summary>
    /// 文件销毁, 支持由逗号间隔的文件名批量销毁
    /// </summary>
    /// <param name="fileNames"></param>
    /// <returns></returns>
    [HttpDelete("Destory")]
    public virtual async Task<IActionResult> DestoryFilesAsync(string fileNames)
    {
        var files = fileNames.Split(AppSettings.CHAR_COMMA, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        if (files.Length != 0)
        {
            await _fileService.DestoryFilesAsync(files);
        }

        return Ok();
    }
}

/// <summary>
/// 字符串主键的基于 IAttachmentService 附件及文件操作类服务
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
[Authorize]
[ApiController]
public abstract class AttachmentServiceController<TDbContext>(
    ILogger<AttachmentServiceController<TDbContext>> logger,
    IDataService<TDbContext, Attachment> dataService,
    IAttachmentService<TDbContext> attachmentService,
    IFileService fileService) :
    AttachmentServiceController<TDbContext, Attachment, string>(logger, dataService, attachmentService, fileService)
    where TDbContext : DbContext
{ }